package com.explorex.infra.puma.gateway.netty.common.security;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.KeyAgreement;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static javax.xml.bind.DatatypeConverter.parseHexBinary;
import static javax.xml.bind.DatatypeConverter.printHexBinary;

/**
 * @author: JacceYang
 * @createTime: 2022/09/07 10:18
 * @description:
 */
@Slf4j
public class EDCHUtil {


    public static KeyPair generateKeyPair() {
        try {
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
            kpg.initialize(256);
            return kpg.generateKeyPair();
        } catch (Exception e) {
            // do nothing
            log.error("generateKeyPair exeception", e);
        }
        return null;
    }

    public static byte[] generateSharKey(byte[] otherPk, KeyPair kp) {

        try {
            byte[] ourPk = kp.getPublic().getEncoded();
            log.info("public key:{}", printHexBinary(ourPk));

            KeyFactory kf = KeyFactory.getInstance("EC");
            X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(otherPk);
            PublicKey otherPublicKey = kf.generatePublic(pkSpec);

            // performs key agreement
            KeyAgreement ka = KeyAgreement.getInstance("ECDH");
            ka.init(kp.getPrivate());
            ka.doPhase(otherPublicKey, true);

            byte[] sharedSecret = ka.generateSecret();
            log.info("Shared secret: {}", printHexBinary(sharedSecret));

            MessageDigest hash = MessageDigest.getInstance("SHA-256");
            hash.update(sharedSecret);
            // Simple deterministic ordering
            List<ByteBuffer> keys = Arrays.asList(ByteBuffer.wrap(ourPk), ByteBuffer.wrap(otherPk));
            Collections.sort(keys);
            hash.update(keys.get(0));
            hash.update(keys.get(1));
            return hash.digest();
        } catch (Exception e) {

        }

        return null;
    }

    public static void main(String[] args) throws Exception {
        byte[] otherPk = parseHexBinary("3059301306072A8648CE3D020106082A8648CE3D03010703420004A1068DE1FCFA9E2CB53064F5755E7A760F2243CBE944E341DCC4ED5F058BC68E5B61E15138DA99A1C9C4B7A902743C09AA8CE3F356E929E353470C12E734669C");
        byte[] derivedKey = generateSharKey(otherPk, generateKeyPair());
        System.out.printf("Final key: %s%n", printHexBinary(derivedKey));

        long currentTimeMillis = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            String msg = "hello world xdfefeefef sdfdsfs  fdfsdf" + i;
            byte[] decrypt = AESUtil.encrypt(derivedKey, msg.getBytes(StandardCharsets.UTF_8));
            byte[] decrypt1 = AESUtil.decrypt(derivedKey, decrypt);
            System.out.println(new String(decrypt1));
        }
        System.out.printf("time escape= %d", System.currentTimeMillis() - currentTimeMillis);
    }

}
